import uuid

from pydantic import BaseModel
from typing import Dict
import datetime
import pandas as pd
import numpy as np
import shutil
from pathlib import Path
import multiprocessing
import json
import os
import warnings

warnings.filterwarnings("ignore")


class NumpyJSONEncoder(json.JSONEncoder):
    """处理NumPy数据类型和datetime的JSON编码器"""
    def default(self, obj):
        # 处理NumPy整数类型
        if isinstance(obj, (np.integer, np.int32, np.int64)):
            return int(obj)
        # 处理NumPy浮点类型
        elif isinstance(obj, (np.floating, np.float32, np.float64)):
            return float(obj)
        # 处理NumPy布尔类型
        elif isinstance(obj, np.bool_):
            return bool(obj)
        # 处理NumPy数组
        elif isinstance(obj, np.ndarray):
            return obj.tolist()
        # 默认处理
        return super().default(obj)


class Performance(BaseModel):
    """
    用于记录策略表现
    """
    annualized_return: float = 0.0  # 年化收益率
    annualized_return_no_fee: float = 0.0  # 无手续费的年化收益率
    annualized_volatility: float = 0.0  # 年化波动率
    annualized_shape: float = 0.0  # 夏普比率
    turnover: float = 0.0  # 换手率, 是日均口径换手率
    margin: float = 0.0  # 代表平均每次收益获利水平，衡量盈利是否覆盖手续费
    fitness: float = 0.0  # 综合衡量夏普比率和Margin的指标
    excess_return: float = 0.0  # 年化超额收益
    relative_return: float = 0.0  # 年化相对收益倍数
    information_ratio: float = 0.0  # 信息比率，衡量超额收益的综合指标
    max_drawdown: float = 0.0  # 最大回撤
    calmar_ratio: float = 0.0  # 综合衡量年化收益和最大回撤的指标
    yearly_count: float = 0.0  # 平均年交易次数
    winning_rate: float = 0.0  # 胜率
    profit_loss_ratio: float = 0.0  # 盈亏比
    kelly_fraction: float = 0.0  # 用凯利公式计算的合理配置仓位


class VolatilityStrategy(object):
    """
    开仓: 区间收益率大于0, 断线波动率 > 长线波动率 + 倍数*长线波动率标准差
    平仓1: 短线波动率 < 长线波动率 + 倍数*长线波动率标准差
    平仓2: 短线波动率 < 长线波动率
    """

    def __init__(self, frequency):
        self.frequency = frequency  # 回测频率
        self.data_begin_date = datetime.date(2015, 1, 1)  # 数据开始日期 数据开始日期小于回测开始日期 预留一些数据计算指标
        self.backtest_begin_date = datetime.date(2017, 1, 1)  # 回测开始日期
        self.backtest_end_date = datetime.date(2025, 8, 31)  # 回测结束日期
        self.trading_days_one_year = 365  # 一年的交易日数量
        self.risk_free_rate = 2.0  # 无风险利率
        self.btc_df: pd.DataFrame = None  # 保存btc的价格曲线
        self.equity_curve_df_dict: Dict[str, pd.DataFrame] = {}  # 保存资产曲线
        self.trade_log_df_dict: Dict[str, pd.DataFrame] = {}  # 保存交易日志
        self.year_list = []  # 回测的年份列表

    def backtest(self, vol_l, vol_s, return_period, std_multiplier):
        if self.frequency == "1h":
            path = "BTC_kline_1h_merge.csv"
        elif self.frequency == "3h":
            path = "BTC_kline_3h_merge.csv"
        elif self.frequency == "1d":
            path = "BTC_kline_1d_merge.csv"
        else:
            raise Exception("Frequency must be 1h or 3h or 1d!")
        print(
            f"frequency:{self.frequency}, vol_l:{vol_l}, vol_s:{vol_s}, return_period:{return_period},"
            f"std_multiplier:{std_multiplier} 开始回测")
        self.btc_df = pd.read_csv(path)
        self.btc_df["datetime"] = pd.to_datetime(self.btc_df["datetime"])
        self.btc_df["date"] = self.btc_df["datetime"].dt.date
        self.btc_df = self.btc_df[self.btc_df['date'] >= self.data_begin_date]
        self.btc_df = self.btc_df[self.btc_df['date'] <= self.backtest_end_date]
        self.get_buy_sell_signals(vol_l, vol_s, return_period, std_multiplier)
        self.volatility_strategy("v1")
        self.volatility_strategy("v2")
        self.get_performance_by_begin_date(vol_l, vol_s, return_period, std_multiplier)
        self.get_performance_by_years(vol_l, vol_s, return_period, std_multiplier)
        self.save_file(vol_l, vol_s, return_period, std_multiplier)

    def get_performance_by_begin_date(self, vol_l, vol_s, return_period, std_multiplier):
        """
        按照开始日期计算表现
        :return:
        """
        for version in ["v1", "v2"]:
            version_equity_curve_df = self.equity_curve_df_dict[version]
            version_trade_log_df = self.trade_log_df_dict[version]

            equity_curve_df = version_equity_curve_df.copy()
            hold_btc_df = self.btc_df[self.btc_df['date'] >= self.backtest_begin_date]
            trade_log_df = version_trade_log_df.copy()
            if trade_log_df.empty:
                print(f"frequence:{self.frequency}, 没有发生交易")
            if self.frequency in ("1h", "3h"):
                equity_curve_df = equity_curve_df.groupby("date").last()
                hold_btc_df = hold_btc_df.groupby("date").last()
            nav0_ser = equity_curve_df['equity0'] / equity_curve_df['equity0'].iloc[0]
            nav2_ser = equity_curve_df['equity2'] / equity_curve_df['equity2'].iloc[0]
            hold_btc_nav_ser = hold_btc_df["close"] / hold_btc_df["close"].iloc[0]
            # margin的计算需要用nav0(不含手续费) 其他指标的计算需要用nav2(双边千分之2)
            performance = self.cal_performance(nav2_ser, hold_btc_nav_ser, trade_log_df.copy())
            performance2 = self.cal_performance(nav0_ser, hold_btc_nav_ser, trade_log_df.copy())
            performance.margin = performance2.margin
            performance.annualized_return_no_fee = performance2.annualized_return
            performance_dict = performance.dict()
            performance_dict.update({'version': version, 'time': "all", 'vol_l': vol_l, 'vol_s': vol_s,
                                     'return_period': return_period, 'std_multiplier': std_multiplier})
            with open(f'{self.frequency}/performance/{uuid.uuid4()}.json', 'w', encoding='utf-8') as f:
                json.dump(performance_dict, f, cls=NumpyJSONEncoder)

    def get_performance_by_years(self, vol_l, vol_s, return_period, std_multiplier):
        """
        逐年分析
        :param nav_df:
        :param trade_log_df:
        :param hold_btc_df:
        :param performance_map:
        :return:
        """
        for version in ["v1", "v2"]:
            version_equity_curve_df = self.equity_curve_df_dict[version]
            version_trade_log_df = self.trade_log_df_dict[version]
            equity_curve_df = version_equity_curve_df.copy()
            trade_log_df = version_trade_log_df.copy()
            equity_curve_df['year'] = equity_curve_df['date'].apply(lambda x: x.year)
            self.btc_df['year'] = self.btc_df['date'].apply(lambda x: x.year)
            trade_log_df['year'] = trade_log_df['date'].apply(lambda x: x.year)

            for year in equity_curve_df["year"].unique():
                if year not in self.year_list:
                    self.year_list.append(year)
                year_equity_curve_df = equity_curve_df[equity_curve_df["year"] == year]
                year_hold_btc_df = self.btc_df[self.btc_df['year'] == year]
                if self.frequency in ("1h", "3h"):
                    year_equity_curve_df = year_equity_curve_df.groupby("date").last()
                    year_hold_btc_df = year_hold_btc_df.groupby("date").last()
                nav0_ser = year_equity_curve_df['equity0'] / year_equity_curve_df['equity0'].iloc[0]
                nav2_ser = year_equity_curve_df['equity2'] / year_equity_curve_df['equity2'].iloc[0]
                hold_btc_nav_ser = year_hold_btc_df['close'] / year_hold_btc_df['close'].iloc[0]
                year_trade_log_df = trade_log_df[trade_log_df['year'] == year]
                if year_trade_log_df.empty:
                    print(f"frequence:{self.frequency}, year:{year}没有发生交易")
                # 计算margin 需要用nav0的净值曲线(无手续费), 其他指标需要nav2的净值曲线(双边千2)
                performance = self.cal_performance(nav2_ser, hold_btc_nav_ser, year_trade_log_df.copy())
                performance2 = self.cal_performance(nav0_ser, hold_btc_nav_ser, year_trade_log_df.copy())
                performance.margin = performance2.margin
                performance.annualized_return_no_fee = performance2.annualized_return
                performance_dict = performance.dict()
                performance_dict.update({'version': version, 'time': year, 'vol_l': vol_l, 'vol_s': vol_s,
                                         'return_period': return_period, 'std_multiplier': std_multiplier})
                with open(f'{self.frequency}/performance/{uuid.uuid4()}.json', 'w', encoding='utf-8') as f:
                    json.dump(performance_dict, f, cls=NumpyJSONEncoder)

    def get_buy_sell_signals(self, vol_l, vol_s, return_period, std_multiplier):
        """
        得到买卖信号
        :return:
        """
        returns = self.btc_df["close"].pct_change()
        self.btc_df["long_vol"] = returns.rolling(window=vol_l).std()
        self.btc_df["long_vol_std"] = self.btc_df["long_vol"].rolling(window=vol_l).std()
        self.btc_df["short_vol"] = returns.rolling(window=vol_s).std()
        self.btc_df['vol_threshold'] = self.btc_df['long_vol'] + std_multiplier * self.btc_df['long_vol_std']
        self.btc_df['n_days_return'] = self.btc_df['close'].pct_change(return_period)

        cond1 = self.btc_df["short_vol"].shift(1) <= self.btc_df["vol_threshold"].shift(1)  # 之前短线波动率小于阈值
        cond2 = self.btc_df["short_vol"] > self.btc_df["vol_threshold"]  # 现在短线波动率大于阈值
        cond3 = self.btc_df['n_days_return'] > 0  # 区间收益率大于0
        self.btc_df.loc[cond1 & cond2 & cond3, "signal"] = 1

        cond4 = self.btc_df["short_vol"].shift(1) >= self.btc_df["vol_threshold"].shift(1)  # 之前短线波动率大于于阈值
        cond5 = self.btc_df["short_vol"] < self.btc_df["vol_threshold"]  # 现在短线波动率小于阈值
        self.btc_df.loc[cond4 & cond5, "signal1"] = -1
        cond6 = self.btc_df["short_vol"].shift(1) >= self.btc_df["long_vol"].shift(1)  # 之前短线波动率大于长线波动率
        cond7 = self.btc_df["short_vol"] < self.btc_df["long_vol"]  # 现在短线波动率小于长线波动率
        self.btc_df.loc[cond6 & cond7, "signal2"] = -1
        self.btc_df[["signal", "signal1", "signal2"]] = self.btc_df[["signal", "signal1", "signal2"]].fillna(0)

    def volatility_strategy(self, version):
        """v1:signal1=-1平仓, v2: signal2=-1平仓"""
        # 初始化仓位和净值
        position = 0  # 0表示空仓，1表示多仓
        # 初始资金10000
        equity0 = [10000]  # 没有手续费
        equity1 = [10000]  # 双边手续费千分之一
        fee_rate1 = 0.001
        equity2 = [10000]  # 双边手续费千分之二
        fee_rate2 = 0.002
        trade_log = []
        pre_price = 0
        truncate_btc_df = self.btc_df[self.btc_df['date'] >= self.backtest_begin_date]
        for _, row in truncate_btc_df.iterrows():
            # 开仓条件: 突破上轨且没有仓位
            close_cond1 = version == "v1" and position == 1 and row['signal1'] == -1  # 平仓条件1
            close_cond2 = version == "v2" and position == 1 and row['signal2'] == -1  # 平仓条件2
            if position == 0 and row['signal'] == 1:
                position = 1
                entry_price = row["close"]
                trade_log.append({
                    'datetime': row["datetime"],
                    'action': 'BUY',
                    'price': entry_price,
                })
                equity0.append(equity0[-1])
                equity1.append(equity1[-1] * (1 - fee_rate1))
                equity2.append(equity2[-1] * (1 - fee_rate2))
            # v1:signal1=-1平仓 v2: signal2=-1平仓
            elif close_cond1 or close_cond2:
                position = 0
                exit_price = row["close"]
                equity0.append(equity0[-1] * (row["close"] / pre_price))
                equity1.append(equity1[-1] * (row["close"] / pre_price) * (1 - fee_rate1))
                equity2.append(equity2[-1] * (row["close"] / pre_price) * (1 - fee_rate2))
                trade_log.append({
                    'datetime': row["datetime"],
                    'action': 'SELL',
                    'price': exit_price,
                    'return0': (exit_price - entry_price) / entry_price,
                    'return1': (exit_price - entry_price - (entry_price + exit_price) * fee_rate1) / entry_price,
                    'return2': (exit_price - entry_price - (entry_price + exit_price) * fee_rate2) / entry_price,
                })
            # 持有仓位时更新净值
            elif position == 1:
                assert pre_price > 0
                equity0.append(equity0[-1] * (row["close"] / pre_price))
                equity1.append(equity1[-1] * (row["close"] / pre_price))
                equity2.append(equity2[-1] * (row["close"] / pre_price))
            else:
                equity0.append(equity0[-1])
                equity1.append(equity1[-1])
                equity2.append(equity2[-1])
            pre_price = row["close"]
        equity0.pop(0)
        equity1.pop(0)
        equity2.pop(0)
        # 转换为DataFrame
        equity_curve_df = pd.DataFrame({"equity0": equity0,
                                        "equity1": equity1,
                                        "equity2": equity2})
        equity_curve_df["datetime"] = truncate_btc_df["datetime"].reset_index(drop=True)
        equity_curve_df["date"] = truncate_btc_df["date"].reset_index(drop=True)
        trade_log_df = pd.DataFrame(trade_log)
        if not trade_log_df.empty:
            trade_log_df["date"] = trade_log_df["datetime"].dt.date
        else:
            trade_log_df = pd.DataFrame(columns=['datetime', 'action', 'price', 'return', 'date'])
        self.equity_curve_df_dict[version] = equity_curve_df
        self.trade_log_df_dict[version] = trade_log_df

    @staticmethod
    def get_trade_count(trade_log_df):
        """开半仓只算交易0.5次,开全仓才算交易1次"""
        count_ser = trade_log_df["action"].apply(lambda x: 0.5 if "50" in x else 1)
        return count_ser.sum()

    def cal_performance(self, nav_series, nav_series_benchmark, trade_log_df):
        """
        计算策略表现
        :param nav_series:  策略每日净值曲线
        :param nav_series_benchmark:  基准每日净值曲线
        :param trade_log_df:  期间的交易记录
        :return:
        """
        performance_obj = Performance()  # 创建一个performance对象
        if nav_series.max() == nav_series.min() == 1 and trade_log_df.empty:  # 期间都是空仓, 没有买卖行为
            no_performance = Performance(annualized_return=np.nan,
                                         annualized_return_no_fee=np.nan,
                                         annualized_volatility=np.nan,
                                         annualized_shape=np.nan,
                                         turnover=np.nan,
                                         margin=np.nan,
                                         fitness=np.nan,
                                         excess_return=np.nan,
                                         relative_return=np.nan,
                                         information_ratio=np.nan,
                                         max_drawdown=np.nan,
                                         calmar_ratio=np.nan,
                                         yearly_count=np.nan,
                                         winning_rate=np.nan,
                                         profit_loss_ratio=np.nan,
                                         kelly_fraction=np.nan)
            return no_performance
        # 日收益率
        daily_returns = nav_series.pct_change().dropna()
        benchmark_returns = nav_series_benchmark.pct_change().dropna()
        # 总收益率
        total_return = nav_series.iloc[-1] / nav_series.iloc[0] - 1
        # 年化收益率
        n_days = len(nav_series)  # 回测期间的交易天数
        annualized_return = (1 + total_return) ** (self.trading_days_one_year / n_days) - 1
        annualized_return = annualized_return * 100
        performance_obj.annualized_return = annualized_return
        # 年化波动率
        annualized_volatility = daily_returns.std() * np.sqrt(self.trading_days_one_year)
        annualized_volatility = annualized_volatility * 100
        performance_obj.annualized_volatility = annualized_volatility
        # 夏普比率 risk_free_rate=2.0
        annualized_shape = (annualized_return - self.risk_free_rate) / annualized_volatility if (
                annualized_volatility != 0) else np.nan
        performance_obj.annualized_shape = annualized_shape
        # 平均年交易次数
        if "BUY_50%" in set(trade_log_df["action"]):
            yearly_count = self.get_trade_count(trade_log_df) / (n_days / 365)
        else:
            yearly_count = len(trade_log_df) / (n_days / 365)
        performance_obj.yearly_count = yearly_count
        turnover = yearly_count / 365 * 100
        performance_obj.turnover = turnover

        # margin 以千分比的形式呈现  Margin=DailyReturn/TurnOver
        # 用年化return求daily_return
        daily_return = (annualized_return / 100 + 1) ** (1 / 365) - 1
        margin = daily_return * 100 / turnover if turnover != 0 else np.nan  # 乘以100是为了和turnover保持单位统一
        # fitness, Fitness=Annualized Sharpe×Sqrt(Abs(Margin))
        fitness = annualized_shape * np.sqrt(abs(margin))
        # 先计算fitness再以千分比的形式呈现
        margin = margin * 1000
        performance_obj.margin = margin
        performance_obj.fitness = fitness

        # max_drawdown
        peak = nav_series.expanding().max()
        drawdown = (nav_series - peak) / peak
        max_drawdown = abs(drawdown.min())
        max_drawdown = max_drawdown * 100
        performance_obj.max_drawdown = max_drawdown

        # 超额收益指标
        benchmark_annualized_return = (nav_series_benchmark.iloc[-1] / nav_series_benchmark.iloc[0]) ** (
                self.trading_days_one_year / n_days) - 1
        benchmark_annualized_return = benchmark_annualized_return * 100  # benchmark的年化收益率
        performance_obj.excess_return = annualized_return - benchmark_annualized_return

        # 年化相对收益倍数
        performance_obj.relative_return = (annualized_return / 100 + 1) / (benchmark_annualized_return / 100 + 1)

        # information_ration
        # benchmark_return 是持有BTC的每日return序列 trading_days=365
        excess_returns = daily_returns.reset_index(drop=True) - benchmark_returns.reset_index(drop=True)
        excess_returns_percent = excess_returns * 100
        information_ratio = performance_obj.excess_return / (
                excess_returns_percent.std() * np.sqrt(self.trading_days_one_year))
        performance_obj.information_ratio = information_ratio

        # calmar ratio, Calmar Ratio = Annualized Return/Max Drawdown
        calmar_ratio = annualized_return / abs(max_drawdown) if max_drawdown != 0 else np.nan  # 上下都乘了100 不用处理
        performance_obj.calmar_ratio = calmar_ratio

        # 计算胜率 盈亏比 kelly_fraction
        sell_df = trade_log_df[trade_log_df['action'].str.contains('SELL')]
        if len(sell_df) == 0:
            performance_obj.winning_rate = np.nan  # 胜率置位空
            performance_obj.profit_loss_ratio = np.nan  # 盈亏比置位空
            performance_obj.kelly_fraction = np.nan  # kelly_fraction置位空
        else:
            # 胜率
            winning_rate = len(sell_df[sell_df["return2"] > 0]) / len(sell_df)
            performance_obj.winning_rate = winning_rate * 100
            # 盈亏比
            win_df = sell_df[sell_df["return2"] > 0]
            lose_df = sell_df[sell_df["return2"] < 0]
            performance_obj.profit_loss_ratio = abs(win_df["return2"].mean() / lose_df["return2"].mean())
            # 用凯利公式计算的合理配置仓位
            performance_obj.kelly_fraction = (performance_obj.profit_loss_ratio * winning_rate - (1 - winning_rate)) / (
                performance_obj.profit_loss_ratio)

        return performance_obj

    def save_file(self, vol_l, vol_s, return_period, std_multiplier):
        """
        保存所有文件
        :param ma_l:
        :param ma_s:
        :return:
        """
        for version in ["v1", "v2"]:
            version_equity_curve_df = self.equity_curve_df_dict[version]
            version_trade_log_df = self.trade_log_df_dict[version]

            equity_curve_df = version_equity_curve_df.copy()
            hold_btc_df = self.btc_df[self.btc_df['date'] >= self.backtest_begin_date]
            trade_log_df = version_trade_log_df.copy()
            trade_log_df.to_csv(
                f"{self.frequency}/trade_log/trade_log_{vol_l}_{vol_s}_{return_period}_{std_multiplier}_{version}.csv",
                index=False)
            if self.frequency in ("1h", "3h"):
                equity_curve_df = equity_curve_df.groupby("date").last()
                hold_btc_df = hold_btc_df.groupby("date").last()
                hold_btc_df.reset_index(drop=False, inplace=True)
            nav0_ser = equity_curve_df['equity0'] / equity_curve_df['equity0'].iloc[0]
            nav1_ser = equity_curve_df['equity1'] / equity_curve_df['equity1'].iloc[0]
            nav2_ser = equity_curve_df['equity2'] / equity_curve_df['equity2'].iloc[0]
            hold_btc_nav_ser = hold_btc_df["close"] / hold_btc_df["close"].iloc[0]

            nav_df = pd.DataFrame({"date": hold_btc_df["date"].values,
                                   "nav0": nav0_ser.values,
                                   "nav1": nav1_ser.values,
                                   "nav2": nav2_ser.values,
                                   "nav(hold_btc)": hold_btc_nav_ser.values
                                   })
            nav_df.to_csv(f"{self.frequency}/nav/nav_{vol_l}_{vol_s}_{return_period}_{std_multiplier}_{version}.csv",
                          index=False)


def delete_all_folders(current_dir="."):
    """
    删除当前目录下的所有文件夹（保留文件）
    """
    current_path = Path(current_dir)

    if not current_path.exists():
        print("当前路径不存在！")
        return

    folders_deleted = 0
    errors = 0

    # 遍历当前目录下的所有项目
    for item in current_path.iterdir():
        if item.is_dir():
            try:
                # 使用 shutil.rmtree 删除文件夹及其内容
                shutil.rmtree(item)
                print(f"✅ 已删除文件夹: {item.name}")
                folders_deleted += 1
            except Exception as e:
                print(f"❌ 删除文件夹失败 {item.name}: {e}")
                errors += 1

    print(f"\n操作完成！删除了 {folders_deleted} 个文件夹，{errors} 个错误")


def save_performance(frequency):
    # 调整一下指标的顺序
    columns = ["version", "vol_l", "vol_s", "return_period", "std_multiplier",
               "annualized_shape", "annualized_return",
               "annualized_return_no_fee",
               "excess_return",
               "calmar_ratio",
               "yearly_count", "margin", "winning_rate", "profit_loss_ratio",
               "kelly_fraction", "annualized_volatility",
               "turnover", "fitness", "relative_return", "max_drawdown", "information_ratio"]
    results = []
    json_files = os.listdir(f"{frequency}/performance")
    for json_file in json_files:
        with open(f"{frequency}/performance/{json_file}") as fp:
            json_data = json.load(fp)
            results.append(json_data)
    results_df = pd.DataFrame(results)

    all_df = results_df[results_df["time"] == "all"]
    all_df = all_df[columns]
    all_df.sort_values(by=['version', 'vol_l', 'vol_s', 'return_period', 'std_multiplier'], inplace=True)
    all_df.to_csv(f"{frequency}/result/backtest_performance.csv", index=False)

    year_df = results_df[results_df["time"] != "all"]
    year_df.rename(columns={"time": "year"}, inplace=True)
    year_df = year_df[['year'] + columns]
    year_df.sort_values(by=['year','version', 'vol_l', 'vol_s', 'return_period', 'std_multiplier'], inplace=True)
    year_df.to_csv(f"{frequency}/backtest_performance_by_year.csv", index=False)


def main():
    print(datetime.datetime.now())
    delete_all_folders()
    for frequency in ["1d"]:
        os.makedirs(f"{frequency}/trade_log")
        os.makedirs(f"{frequency}/nav")
        os.makedirs(f"{frequency}/png")
        os.makedirs(f"{frequency}/result")
        os.makedirs(f"{frequency}/performance")
        vol_l_s_list = [3, 5, 7, 10, 14, 20, 30, 40, 60, 90]  # 计算波动率用到的参数
        return_periods = [3, 5, 7]  # 计算区间收益率用到的参数
        std_multipliers = [0.5, 1, 1.5, 2, 2.5]  # 标准差倍数
        params = []
        for vol_l in vol_l_s_list:
            for vol_s in vol_l_s_list:
                if vol_l <= vol_s:
                    continue
                for return_period in return_periods:
                    for std_multiplier in std_multipliers:
                        params.append((vol_l, vol_s, return_period, std_multiplier))
        with multiprocessing.Pool(60) as pool:
            backtest_obj = VolatilityStrategy(frequency)
            pool.starmap(backtest_obj.backtest, params)
        save_performance(frequency)
    print(datetime.datetime.now())


if __name__ == "__main__":
    main()
